package net.alche.fa.core.parse;

import java.util.List;
import net.alche.fa.core.model.Logic;
import net.alche.fa.core.model.FaParam;
import net.alche.fa.core.model.FaValue;
import net.alche.fa.core.FaClassConf;
import net.alche.al.util.AC;
import net.alche.al.util.M;
import net.alche.fa.core.FaMethod;
import java.util.Map;

import javax.swing.Renderer;

import java.util.HashMap;
import java.io.File;
import cn.hutool.core.io.FileUtil;
import java.util.ArrayList;

@SuppressWarnings("all")
public class FavaParseLogicV2 {
  String rootPath = "";

  public void setRootPath(String path) {
    this.rootPath = path;
  }

  public void fillFaBase(List<Logic> logics) {
    if (logics != null && !logics.isEmpty()) {
      for (Logic logic : logics) {
        this.fillFaBase(logic);
        if (logic != null && logic.getChild() != null) {
          this.fillFaBase(logic.getChild());
        }
      }
    }
  }

  public void fillFaBase(Logic logic) {
    if (logic == null) {
      return;
    }
    FaValue fv = FaKeyWord.getBaseFaValue(logic.getObj());
    if (fv != null) {
      logic.setFaObjValue(fv);
    }
    fv = FaKeyWord.getBaseFaValue(logic.getData());
    if (fv != null) {
      logic.setFaDataValue(fv);
    }
    if (logic.getLogicObj() != null) {
      this.fillFaBase(logic.getLogicObj());
    }
    if (logic.getLogicData() != null) {
      this.fillFaBase(logic.getLogicData());
    }
    if (logic.getParam() != null) {
      this.fillFaBase(logic.getParam());
    }
  }

  public FaClassConf parseJsonV2(String fileName, String json) {
    Map<String, Object> mp = AC.json.getMap(json);
    return getFaClassf(mp);
  }

  public FaClassConf getFaClassf(Map<String, Object> mp) {
    FaClassConf fcc = new FaClassConf();
    for (Map.Entry<String, Object> item : mp.entrySet()) {
      Object val = item.getValue();
      switch (item.getKey()) {
        case "methodList": {
          fcc.setMethodList(initFaMethodList((List) val));
          break;
        }
        case "initLogicList": {
          fcc.setInitLogicList(initLogicList((List) val));
          break;
        }
        case "staticLogicList": {
          fcc.setStaticLogicList(initLogicList((List) val));
          break;
        }
        case "varDef": {
          fcc.setVarDef((Map) val);
          break;
        }
        case "def": {
          fcc.setDef((Map) val);
          break;
        }
        case "name": {
          fcc.setName(val.toString());
          break;
        }
        case "extendName": {
          fcc.setExtendName(val.toString());
          break;
        }
        case "inner": {
          fcc.setInner(getInnerParse((Map) val, fcc.name));
          break;
        }
      }
    }
    return fcc;
  }

  Map<String, FaClassConf> getInnerParse(Map<String, Object> mp, String parName) {
    Map<String, FaClassConf> inner = new HashMap();
    for (Map.Entry<String, Object> item : mp.entrySet()) {
      FaClassConf cf = getFaClassf((Map) item.getValue());
      if (cf != null) {
        inner.put(item.getKey(), cf);
      }
    }
    return inner;
  }

  List<FaMethod> initFaMethodList(List<Map> ls) {
    List<FaMethod> ms = new ArrayList<>();
    if (!AC.empty(ls)) {
      for (Map mp : ls) {
        FaMethod me = new FaMethod();
        me.num = Integer.parseInt(M.s(mp, "num"));
        me.methodName = (String) mp.get("methodName");
        me.returnType = (String) mp.get("returnType");
        me.def = (Map) mp.get("def");
        List<Map> list = (List) mp.get("paramList");
        me.paramList = new ArrayList<>();
        if (!AC.empty(list)) {
          FaParam pp = null;
          for (Map pmp : list) {
            pp = new FaParam();
            pp.objTypeName = M.s(pmp, "objTypeName");
            pp.varName = M.s(pmp, "varName");
            String type = M.s(pmp, "type");
            if (AC.notEmpty(type))
              pp.type = (char) type.charAt(0);
            me.paramList.add(pp);
          }
        }
        List<Map> logicList = (List) mp.get("logicList");
        List<Logic> lgList = initLogicList(logicList);
        me.setLogicList(lgList);
        ms.add(me);
      }
    }
    return ms;
  }

  List<Logic> initLogicList(List<Map> ls) {
    List<Logic> ms = new ArrayList<>();
    if (!AC.empty(ls)) {
      for (Map mp : ls) {
        ms.add(initLogic(mp));
      }
    }
    return ms;
  }

  Logic initLogic(Map mp) {
    Logic me = new Logic();
    if (mp.containsKey("num"))
      me.num = M.i(mp, "num");
    if (mp.containsKey("obj"))
      me.obj = M.s(mp, "obj");
    if (mp.containsKey("what"))
      me.what = M.s(mp, "what");
    if (mp.containsKey("data"))
      me.data = M.s(mp, "data");
    if (mp.containsKey("eq"))
      me.eq = M.s(mp, "eq");
    if (mp.containsKey("child")) {
      List<Logic> clog = initLogicList((List) mp.get("child"));
      me.child = clog;
    }
    if (mp.containsKey("param")) {
      List<Logic> clog = initLogicList((List) mp.get("param"));
      me.param = clog;
    }
    if (mp.containsKey("logicObj")) {
      me.logicObj = initLogic((Map) mp.get("logicObj"));
    }
    if (mp.containsKey("logicData")) {
      me.logicData = initLogic((Map) mp.get("logicData"));
    }
    return me;
  }

  public FaClassConf parseJson(String fileName, String json) {
    FaClassConf fcc = null;
    fcc = parseJsonV2(fileName, json);
    // fcc = AC.json.getObj(json, FaClassConf.class);
    // Map map = AC.json.getMap(json);
    if (fcc == null) {
      AC.log("解析flass失败:", fileName);
      return null;
    }
    for (FaMethod fm : fcc.getMethodList()) {
      this.fillFaBase(fm.getLogicList());
    }
    if (fcc.getInner() != null) {
      for (FaClassConf icc : fcc.getInner().values()) {
        if (icc.getMethodList() != null) {
          for (FaMethod fm : icc.getMethodList()) {
            this.fillFaBase(fm.getLogicList());
          }
        }
      }
    }
    this.fillFaBase(fcc.getInitLogicList());
    this.fillFaBase(fcc.getStaticLogicList());
    // AC.log("parseJson", fcc)
    return fcc;
  }

  // 解析flass代码
  // @className 指定文件 , null = 解析全部
  public Map<String, FaClassConf> parse(String className) {
    Map<String, FaClassConf> map = new HashMap<>();
    List<File> fs = this.recurFiles(this.rootPath);
    for (File file : fs) {
      if (this.hasInPath(file.getName(), className)) {
        // AC.log("parse", file.getName())
        String json = FileUtil.readUtf8String(file);
        FaClassConf fcc = this.parseJson(file.getName(), json);
        if (fcc != null) {
          map.put(fcc.getName(), fcc);
        }
      }
    }
    return map;
  }

  private boolean hasInPath(String fileName, String inPath) {
    if (inPath == null) {
      return true;
    }
    fileName = fileName.substring(0, fileName.length() - 6);
    if (("," + inPath + ",").contains(fileName)) {
      return true;
    }
    return false;
  }

  private List recurFiles(String filePath) {
    List list = new ArrayList<>();
    File[] files = FileUtil.ls(filePath);
    if (files != null && files.length > 0) {
      for (File f : files) {
        if (f.isDirectory()) {
          List itemList = this.recurFiles(f.getAbsolutePath());
          if (itemList != null) {
            list.addAll(itemList);
          }
        } else {
          list.add(f);
        }
      }
    }
    if (list.isEmpty()) {
      return null;
    }
    return list;
  }

  // public static void main2(String[] args) {
  // SageBiz sageBiz = new SageBiz();
  // sageBiz.setDiskFileBiz(new DiskFileBiz());
  // try {}
  // // sageBiz.initCtrlV2()
  // catch ( Exception ex) {
  // ex.printStackTrace();
  // }
  // }
}